package com.example.kingdee.sqlTool;


import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONObject;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.TypeReference;
import com.example.kingdee.common.KCloudResult;
import com.example.kingdee.common.PushDownDto;
import com.example.kingdee.common.constant.YiTiConstant;
import com.example.kingdee.entity.CycleTimeVo;
import com.example.kingdee.exception.ProcedureException;
import com.example.kingdee.kingdeeBridge.entity.SrcBillEntry;
import com.example.kingdee.mapper.TBxStMapper;
import com.example.kingdee.sqlTool.block.SqlToolBlock;
import com.example.kingdee.sqlTool.common.DataObject;
import com.example.kingdee.sqlTool.common.QueryObject;
import com.example.kingdee.sqlTool.common.QueryResult;
import com.example.kingdee.sqlTool.singleton.Singleton;
import com.example.kingdee.sqlTool.sqltoolEnum.FormIdEnum;
import com.google.gson.Gson;
import com.kingdee.bos.webapi.entity.RepoRet;
import com.kingdee.bos.webapi.entity.SuccessEntity;
import com.kingdee.bos.webapi.sdk.K3CloudApi;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

import static com.baomidou.mybatisplus.extension.api.Assert.fail;

@Service
public class SqlTool {

    @Autowired
    private SqlToolBlock sqlToolBlock;

    @Autowired
    private TBxStMapper tBxStMapper;

    private static K3CloudApi k3CloudApi;

    private Log logger = LogFactory.getLog(SqlTool.class);

    static {
        try {
            k3CloudApi = Singleton.getInstance();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    //拼接物料同步日志信息
    public static String modifyItemSyncLogInfo(List<Object> objectIdList, String type, String isExist, String msg){
        return type + YiTiConstant.SEPARATOR +
                objectIdList.toString() + YiTiConstant.SEPARATOR +
                isExist + YiTiConstant.SEPARATOR +
                getNowForString() + YiTiConstant.SEPARATOR +
                msg;
    }

    /**
     * 获取当前时间，String类型
     *
     * @return
     */
    public static String getNowForString() {
        return DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now());
    }

    /**
     * 克隆JSONObject
     *
     * @param jsonObject
     * @return
     */
    public JSONObject cloneJSONObject(JSONObject jsonObject) {
        JSONObject newJSONObject = new JSONObject();
        jsonObject.forEach((k, v) -> {
            newJSONObject.put(k, v);
        });
        return newJSONObject;
    }



    /**
     * 查询并构建返回结果
     *
     * @param
     */
    public ArrayList<HashMap<String, Object>> weaveResult(QueryObject select, ArrayList<String> resultKeyArray){
        QueryResult queryResult;
        try {
            queryResult = selectForQueryObject(select);
        }catch (Exception e){
            e.printStackTrace();
            throw new ProcedureException("无法调用云星空接口");
        }
        return getResult(resultKeyArray, queryResult);
    }

    private ArrayList<HashMap<String, Object>> getResult(ArrayList<String> resultKeyArray, QueryResult queryResult) {
        if (queryResult.getCode().equals("500")){
            throw new ProcedureException("查询失败：" + queryResult.getMsg());
        }

        ArrayList<HashMap<String, Object>> data = queryResult.getRecords();
        ArrayList<String> selectArray = queryResult.getSelectArray();

        ArrayList<HashMap<String, Object>> result = new ArrayList<>();
        for (HashMap<String, Object> datum : data) {
            HashMap<String, Object> resultRow = new HashMap<>();
            for (int i = 0; i < selectArray.size(); i++) {
                resultRow.put(resultKeyArray.get(i), datum.get(selectArray.get(i)));
            }
            result.add(resultRow);
        }
        return result;
    }

    /**
     * 查询接口
     * @param queryObject
     */
    public QueryResult selectForQueryObject(QueryObject queryObject) throws Exception {
        if (queryObject.getFormId() == null) {
            throw new ProcedureException("请设置QueryRequest的TableName");
        }
        QueryResult queryResult = new QueryResult();
        //解析查询语句
        String fieldKeys;
        ArrayList<String> selectArray = queryObject.getSelectArray();
        if (selectArray.size() > 0) {
            fieldKeys = sqlToolBlock.getSelectSqlBySelectArray(selectArray);
            queryObject.put("FieldKeys", fieldKeys);
            queryObject.remove("selectArray");
        }else {
            throw new ProcedureException("要查询的字段不可为空");
        }

        //解析条件语句
        String whereSql = "";
        if (queryObject.getCondition().size() > 0) {
            whereSql = sqlToolBlock.getWhereSqlByCondition(queryObject.getCondition());
            queryObject.put("FilterString", whereSql);
            queryObject.remove("condition");
        }

        queryObject.initParam();

        String data = JSON.toJSONString(queryObject);
        List<List<Object>> result = k3CloudApi.executeBillQuery(data);
        //处理返回结果
        sqlToolBlock.initQueryResult(selectArray, result, queryResult);
        return queryResult;
    }

    /**
     * 根据表名与主键数组反审核单据
     *
     * @param dataObject
     */
    public Map<String, Object> unAuditBatchData(DataObject dataObject){
        String formId = dataObject.getFormId();
        if (StringUtils.isEmpty(formId)){
            throw new ProcedureException("表单id不能为空");
        }else {
            dataObject.remove("formid");
        }
        String query = JSON.toJSONString(dataObject);
        try {
            String submit = k3CloudApi.unAudit(formId, query);
            return getKCloudResult(submit);
        } catch (Exception e) {
            throw new ProcedureException("提交失败");
        }
    }

    //发送httpPost请求
    public static String sendHttpPost(String url, HashMap<String, String> param){
        String JSONBody = JSON.toJSONString(param);
        CloseableHttpClient httpClient = HttpClients.createDefault();
        //设置超时时间
        RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(5000).setConnectionRequestTimeout(1000).setSocketTimeout(5000).build();
        HttpPost httpPost = new HttpPost(url);
        httpPost.setConfig(requestConfig);
        httpPost.addHeader("Content-Type", "application/json;charset=utf-8");
        httpPost.setEntity(new StringEntity(JSONBody, "utf-8"));
        CloseableHttpResponse response;
        try {
            response = httpClient.execute(httpPost);
            HttpEntity entity = response.getEntity();
            String responseContent = EntityUtils.toString(entity, "UTF-8");
            response.close();
            httpClient.close();
            return responseContent;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }


    /**
     * 根据数据实体修改或添加数据
     *
     * @param dataObject
     */
    public Map<String, Object> editForDataObject(DataObject dataObject) throws Exception {
        String formId = dataObject.getFormId();
        if (StringUtils.isEmpty(formId)){
            throw new ProcedureException("表单id不能为空");
        }else {
            dataObject.remove("formid");
        }
        String query = JSON.toJSONString(dataObject);
        String save = k3CloudApi.save(formId, query);
        return getKCloudResult(save);
    }

    /**
     * 根据表名与主键数组批量删除
     *
     * @param dataObject
     */
    public void deleteBatchData(DataObject dataObject) throws Exception {
        String formId = dataObject.getFormId();
        if (StringUtils.isEmpty(formId)){
            throw new ProcedureException("表单id不能为空");
        }else {
            dataObject.remove("formid");
        }
        String query = JSON.toJSONString(dataObject);
        k3CloudApi.delete(formId, query);
    }

    /**
     * 根据表名与主键数组批量审批单据
     *
     * @param dataObject
     */
    public Map<String, Object> auditBatchData(DataObject dataObject){
        String formId = dataObject.getFormId();
        if (StringUtils.isEmpty(formId)){
            throw new ProcedureException("表单id不能为空");
        }else {
            dataObject.remove("formid");
        }
        String query = JSON.toJSONString(dataObject);
        try {
            String audit = k3CloudApi.audit(formId, query);
            return getKCloudResult(audit);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    /**
     * 根据表名与主键数组批量提交单据
     *
     * @param dataObject
     */
    public Map<String, Object> submitBatchData(DataObject dataObject){
        String formId = dataObject.getFormId();
        if (StringUtils.isEmpty(formId)){
            throw new ProcedureException("表单id不能为空");
        }else {
            dataObject.remove("formid");
        }
        String query = JSON.toJSONString(dataObject);
        try {
            String submit = k3CloudApi.submit(formId, query);
            return getKCloudResult(submit);
        } catch (Exception e) {
            throw new ProcedureException("提交失败");
        }
    }

    /**
     * 生产订单行执行
     *
     * @param dataObject
     */
    public Map<String, Object> excuteMoBillNo(DataObject dataObject, String type){
        String formId = dataObject.getFormId();
        if (StringUtils.isEmpty(formId)){
            throw new ProcedureException("表单id不能为空");
        }else {
            dataObject.remove("formid");
        }
        String query = JSON.toJSONString(dataObject);
        try {
            String audit = k3CloudApi.excuteOperation(formId, type, query);
            return getKCloudResult(audit);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    //解析返回结果
    public Map<String, Object> getKCloudResult(String jsonResponse){
        Map<String, Object> result = new HashMap<>();
        com.alibaba.fastjson2.JSONObject jsonObject = JSON.parseObject(jsonResponse);
        String resultStr = jsonObject.get("Result").toString();
        com.alibaba.fastjson2.JSONObject resultObject = JSON.parseObject(resultStr);
        String responseStatusStr = resultObject.get("ResponseStatus").toString();
        KCloudResult kCloudResult = JSON.parseObject(responseStatusStr, new TypeReference<KCloudResult>(){});
        if (!kCloudResult.IsSuccess){
            Map<String, Object> errors = kCloudResult.Errors.get(0);
            String errorMessage = errors.get("Message").toString();
            result.put("code", "500");
            result.put("msg", errorMessage);
        }else {
            Map<String, Object> successEntity = kCloudResult.SuccessEntitys.get(0);
            result.put("code", "200");
            result.put("msg", "成功");
            result.put("primaryKey", successEntity.get("Id"));
            result.put("number", successEntity.get("Number"));
            result.put("index", successEntity.get("DIndex"));
            result.put("billNo", successEntity.get("BillNo"));
        }
        return result;
    }

    //审核单据
    public void auditBill(String billNo, FormIdEnum formIdEnum){
        //提交单据
        DataObject submitDataObject = new DataObject(formIdEnum);
        submitDataObject.addNumbers(billNo);
        Map<String, Object> submitResponse = submitBatchData(submitDataObject);
        if (submitResponse.get("code").equals("500")){
            throw new ProcedureException(submitResponse.get("msg").toString());
        }
        //审核单据
        DataObject auditDataObject = new DataObject(formIdEnum);
        auditDataObject.addNumbers(billNo);
        auditDataObject.addInterFlags(YiTiConstant.CAN_IN_VCHECK_RESULT);
        Map<String, Object> auditResponse = auditBatchData(auditDataObject);
        if (auditResponse.get("code").equals("500")){
            throw new ProcedureException(auditResponse.get("msg").toString());
        }
    }

    //删除单据
    public void deleteBill(String fid, FormIdEnum formIdEnum){
        DataObject dataObject = new DataObject(formIdEnum);
        dataObject.addIds(fid);
        try {
            deleteBatchData(dataObject);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    //生产订单行执行至开工
    public void excuteStartWork(String fid, FormIdEnum formIdEnum, String type){
        DataObject dataObject = new DataObject(formIdEnum);
        dataObject.addIds(fid);
        Map<String, Object> response = excuteMoBillNo(dataObject, type);
        if (response.get("code").equals("500")){
            throw new ProcedureException(response.get("msg").toString());
        }
    }

    //将数组按照指定字段进行分类
    public MultiValueMap<String, Map<String, Object>> getClassFy(List<Map<String, Object>> mapList, String key){
        //将到货计划进行分类
        MultiValueMap<String, Map<String, Object>> classify = new LinkedMultiValueMap<>();
        for (Map<String, Object> map : mapList) {
            String classifyKey = map.get(key) == null ? "" : map.get(key).toString();
            List<Map<String, Object>> maps = classify.get(classifyKey);
            if (maps == null){
                maps = new ArrayList<>();
                maps.add(map);
                classify.put(classifyKey, maps);
            }else {
                maps.add(map);
            }
        }
        return classify;
    }

    //将源单数据按照明细行id分类
    public MultiValueMap<String, SrcBillEntry> getClassFy(List<SrcBillEntry> srcBillEntryList){
        //将到货计划进行分类
        MultiValueMap<String, SrcBillEntry> classify = new LinkedMultiValueMap<>();
        for (SrcBillEntry srcBillEntry : srcBillEntryList) {
            String srcEntryId = srcBillEntry.getEntryId() == null ? "" : srcBillEntry.getEntryId();
            List<SrcBillEntry> billEntryList = classify.get(srcEntryId);
            if (billEntryList == null){
                billEntryList = new ArrayList<>();
                billEntryList.add(srcBillEntry);
                classify.put(srcEntryId, billEntryList);
            }else {
                billEntryList.add(srcBillEntry);
            }
        }
        return classify;
    }


    //将一段日期以指定间隔进行切割
    public List<CycleTimeVo> getCycleList(int cycleNum, String startTime, String endTime){
        try {
            Date endParse = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(endTime);
            Long endLong = endParse.getTime();

            SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//这个是你要转成后的时间的格式
            endTime = sdf.format(new Date(endLong));

            int daysBetweenNum = daysBetween(startTime, endTime);
            int cycleForNum = daysBetweenNum % cycleNum == 0 ? (daysBetweenNum / cycleNum) : (daysBetweenNum / cycleNum) + 1;
            Date startParse = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(startTime);
            Long startLong = startParse.getTime();

            Long calculationLong = startLong;

            List<CycleTimeVo> cycleTimeVoList=new ArrayList();
            if (cycleForNum == 0){
                CycleTimeVo cycleTimeVo=new CycleTimeVo();
                cycleTimeVo.setStartTimeStr(startTime);
                cycleTimeVo.setEndTimeStr(endTime);
                cycleTimeVoList.add(cycleTimeVo);
            }else {
                for (int i = 1; i <= cycleForNum; i++) {

                    String startStr = sdf.format(new Date(calculationLong));
                    Date startStrParse = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(startStr);
                    Long startStrLong = startStrParse.getTime();
                    Long cycleLong = cycleNum*86400000l;
                    calculationLong = startStrLong + cycleLong;
                    String endStr = endTime;
                    if (calculationLong <= endLong) {
                        endStr = sdf.format(new Date(calculationLong));
                    }
                    CycleTimeVo cycleTimeVo=new CycleTimeVo();
                    cycleTimeVo.setStartTimeStr(startStr);
                    cycleTimeVo.setEndTimeStr(endStr);
                    cycleTimeVoList.add(cycleTimeVo);
                }
            }
            return cycleTimeVoList;
        }catch (Exception e){
            throw new ProcedureException();
        }
    }

    public static int daysBetween(String smdate, String bdate) throws ParseException {

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Calendar cal = Calendar.getInstance();
        cal.setTime(sdf.parse(smdate));
        long time1 = cal.getTimeInMillis();
        cal.setTime(sdf.parse(bdate));
        long time2 = cal.getTimeInMillis();
        long between_days = (time2 - time1) / (1000 * 3600 * 24);
        return Integer.parseInt(String.valueOf(between_days));

    }

    //获取仓位传参前缀
    public String getStockLocFlexNumber(String stockLocNumber, String stockNumber) {
        String materialFlexNumber = tBxStMapper.getStockLocFlexNumberNew(stockLocNumber, stockNumber);
        return "FF" + materialFlexNumber;
    }

    //获取仓位传参前缀
    public String getStockOrg(Object outStockNumber) {
        String stockOrgNumber = tBxStMapper.getStockOrgNumber(outStockNumber);
        if (StringUtils.isEmpty(stockOrgNumber)){
            throw new ProcedureException("未查询到仓库使用组织");
        }else {
            return stockOrgNumber;
        }
    }

    public Map<String, String> getStartEndTime(int startTimeType, int endTimeType, int start, int end){
        Map<String, String> result = new HashMap<>();
        //获取当前日期
        Date date = new Date();
        //将时间格式化成yyyy-MM-dd HH:mm:ss的格式
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //创建Calendar实例
        Calendar cal = Calendar.getInstance();
        //设置当前时间
        cal.setTime(date);
        //在当前时间基础上减时间
        cal.add(startTimeType,start);
        String starTimeStr = format.format(cal.getTime());
        result.put("starTime", starTimeStr);
        //在当前时间基础上增加时间
        cal.setTime(date);
        cal.add(endTimeType, end);
        String endTimeStr = format.format(cal.getTime());
        result.put("endTime", endTimeStr);
        return result;
    }
}











